#include "types/common.h"
#include "types/hash.h"
#include "types/errors.h"
#include "types/buffer_info.h"

#ifndef _buffer_mgr_h_
#define _buffer_mgr_h_

#define IS_READ 1
#define IS_WRITE 0

const UINT32 BLOCK_SIZE = 48; 

typedef void (*CommitCallBack) (string &tablename, UINT32 block_num);

class BufferManager
{
public:
	static inline void initialize(int block_count)
	{
		bm = new BufferManager(block_count);
	}
	
	static inline void deinitialize()
	{
		delete bm;
	}
	
	static inline BufferManager & inst()
	{
		if(bm == NULL)
		{
			throw Exception(buffermgr_not_initialized);
		}
		return *bm;
	}
	
	void create_table(string & tblname);
	void create_index(string & tblname);

	void delete_index(string & tblname);
	
	void write_block(string & tblname, UINT32 block, BYTE *buffer);
	void read_block(string & tblname, UINT32 block, BYTE *buffer);
	
	void read_file(string &tblname, UINT32 block_num, BYTE *data);
	void write_file(string &tblname, UINT32 block_num, BYTE *data);
	
	void commit();
	void print(string what); //We will get the string "Buffer" or "hitrate"
	
	inline void reg_commit_callback(CommitCallBack c)
	{
		if(find(commit_callbacks.begin(), commit_callbacks.end(), c) == commit_callbacks.end())
		{
			commit_callbacks.push_back(c);
		}
	}
	
private:
	BufferManager(int block_count);
	~BufferManager();
	
	static BufferManager *bm;
	
	const UINT32 buffer_size; 
	UINT32 num_blocks;
	
	BufferInfo *mru;
	BufferIndex bit;
	int  req_count, miss_count;
	
	vector<CommitCallBack> commit_callbacks;
	
	BufferInfo * load_block(string &tblname, UINT32 block,bool read);
	
	void trigger_commit_callbacks(string &tblname, UINT32 block_num);
		
	inline string dbname(string &tblname)
	{
		return "dbs/" + tblname + ".db";
	}	
};

#endif
